﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RhythmComet.Utils;

namespace RhythmComet.Gameplay
{
    public class Obstacle
    {
        #region Fields and Properties
        Polygon polygon;
        VertexPositionColor[] vertices;
        public Vector3 CenterPosition;
        Vector3 translation;
        float size;
        Vector3 velocity;
        Color color;
        Shape shape;
        int totalOfLines;
        Matrix world;
        bool active;
        float zRotation;
        float rotationFactor;

        BoundingSphere bound;

        public Polygon Polygon
        {
            get { return polygon; }
        }

        public BoundingSphere Bound
        {
            get { return bound; }
        }

        public VertexPositionColor[] Vertices
        {
            get { return vertices; }
        }

        public int TotalLines
        {
            get { return totalOfLines; }
        }

        public Vector3 Velocity
        {
            get { return velocity; }
        }

        public bool Active
        {
            get { return active; }
            set { active = value; }
        }

        public Color Color
        {
            get { return color; }
        }
        #endregion

        public Obstacle()
        {
            this.world = Matrix.Identity;
            active = false;
        }

        public void Initialize(Shape s, Color c, Vector2 offset, float size, Vector2 v, float rotation)
        {
            shape = s;
            this.size = size;
            switch (shape)
            {
                case Shape.Triangle:
                        totalOfLines = 3;
                        polygon = Polygon.CreateTriangle(size);
                        break;
                case Shape.Square:
                        totalOfLines = 4;
                        polygon = Polygon.CreateSquare(size);
                        break;
                case Shape.Hexagon:
                        totalOfLines = 6;
                        polygon = Polygon.CreateHexagon(size);
                        break;
                case Shape.Diamond:
                        totalOfLines = 4;
                        polygon = Polygon.CreateDiamond(size);
                        break;
            }

            vertices = new VertexPositionColor[totalOfLines + 1];
            for (int i = 0; i < totalOfLines + 1; i++)
            {
                vertices[i].Color = c;
            }

            color = c;
            translation = new Vector3(offset, 0.0f);
            Active = true;
            zRotation = 0.0f;
            velocity = new Vector3(v, 0.0f);
            for (int i = 0; i < polygon.Points.Length; i++)
                polygon.Points[i] += translation;
            CenterPosition = new Vector3(translation.X, translation.Y, translation.Z);
            world = world * Matrix.CreateTranslation(translation);
            this.rotationFactor = rotation;
            bound = new BoundingSphere(CenterPosition, size);
        }

        public void Draw(GraphicsDevice graphics, BasicEffect effect)
        {
            if (active)
            {
                world = SpinAroundCenter();
                effect.World = world;
                SetVertices();
                foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                {
                    pass.Begin();
                    graphics.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, vertices, 0, totalOfLines);
                    pass.End();
                }
            }
        }

        public void Update(GameTime gameTime)
        {
            if (active)
            {
                for (int i = 0; i < polygon.Points.Length; i++)
                {
                    polygon.Points[i] += velocity;
                }
                zRotation += rotationFactor;
                if (zRotation >= MathHelper.TwoPi)
                    zRotation = 0.0f;
                else if (zRotation <= 0.0f)
                    zRotation = MathHelper.TwoPi;
                CenterPosition += velocity;
                bound.Center += velocity;
            }
        }

        public void Update(GameTime gameTime, float scale)
        {
            if (active)
            {
                for (int i = 0; i < polygon.Points.Length; i++)
                {
                    polygon.Points[i] += (velocity * scale);
                }
                zRotation += (rotationFactor * scale);
                if (zRotation >= MathHelper.TwoPi)
                    zRotation = 0.0f;
                else if (zRotation <= 0.0f)
                    zRotation = MathHelper.TwoPi;
                CenterPosition += (velocity * scale);
                bound.Center += (velocity * scale);
            }
        }

        private Matrix SpinAroundCenter()
        {
            float xOffset = 0.0f, yOffset = 0.0f;

            for (int i = 0; i < vertices.Length - 1; i++)
            {
                xOffset += vertices[i].Position.X;
                yOffset += vertices[i].Position.Y;
            }
            xOffset /= (vertices.Length - 1);
            yOffset /= (vertices.Length - 1);
            Matrix result = Matrix.CreateTranslation(new Vector3(-xOffset, -yOffset, 0.0f));
            result *= Matrix.CreateRotationZ(zRotation);
            result *= Matrix.CreateTranslation(xOffset, yOffset, 0.0f);

            return result;
        }

        private void SetVertices()
        {
            for (int i = 0; i < totalOfLines; i++)
            {
                vertices[i].Position = polygon.Points[i];
            }
            vertices[totalOfLines].Position = polygon.Points[0];
        }
    }
}
